//
//  NetworkTransport.m
//  Mobile P2P
//
//  Created by Chris Karr on 5/20/08.
//  Copyright 2008 Northwestern University. All rights reserved.
//

#import "NetworkTransport.h"

#define PORT 41264

#define SERVER_NAME @"Host Name"
#define SERVER_PORT @"Host Port"

#define SERVICE @"_mobilep2p._tcp."

@protocol MobileP2PProtocol

- (NSString *) findFile:(NSString *) query;
- (NSData *) downloadFile:(NSString *) path;

@end

@implementation NetworkTransport

@synthesize connection;
@synthesize port;
@synthesize bonjour;
@synthesize lastAccess;
@synthesize cache;

@synthesize currentQuery;

- (NSString *) machineName
{
	CFStringRef nameRef;
	NSString * computerName;
	nameRef = CSCopyMachineName ();
	computerName = [NSString stringWithString:(NSString *) nameRef];
	CFRelease (nameRef);
	
	return computerName;
}

- (void) awakeFromNib
{
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(download:) name:DOWNLOAD_FILE object:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(find:) name:DO_SEARCH object:nil];

	self.cache = [NSMutableDictionary dictionary];
	
	// Init Bonjour listener...
		
	self.port = [[NSSocketPort alloc] initWithTCPPort:PORT];
    self.connection = [[NSConnection alloc] initWithReceivePort:port sendPort:nil];
    [self.connection setRootObject:self];
	
	self.bonjour = [[NSNetService alloc] initWithDomain:@"local" type:SERVICE name:[self machineName] port:PORT];
	[self.bonjour publish];
}

- (void) download:(NSNotification *) theNote
{
	NSDictionary * theFile = [theNote userInfo];

	NSLog (@"download %@", theFile);
	
	NSSocketPort * remotePort = [[NSSocketPort alloc] initRemoteWithTCPPort:[[theFile valueForKey:SERVER_PORT] integerValue] host:[theFile valueForKey:SERVER_NAME]];
	NSConnection * remoteConnection = [NSConnection connectionWithReceivePort:nil sendPort:remotePort];
	
	id<MobileP2PProtocol> remoteObject = (id<MobileP2PProtocol>) [remoteConnection rootProxy];
	
	NSData * data = (NSData *) [remoteObject downloadFile:[theFile valueForKey:PATH]];
	
	NSString * desktop = [NSSearchPathForDirectoriesInDomains (NSDesktopDirectory, NSUserDomainMask, NO) lastObject];
	
	NSString * localPath = [NSString stringWithFormat:@"%@/%@", [desktop stringByExpandingTildeInPath], [[theFile valueForKey:PATH] lastPathComponent]];
	NSLog (@"writing to %@", localPath);
	
	[data writeToFile:localPath atomically:YES];
	
	NSLog (@"data count = %d", [data length]);
	
	[[NSNotificationCenter defaultCenter] postNotificationName:FILE_DOWNLOADED object:self userInfo:theFile];
}

- (void) find:(NSNotification *) theNote
{
	self.currentQuery = [[theNote userInfo] valueForKey:QUERY];
	
	NSNetServiceBrowser * browser = [[NSNetServiceBrowser alloc] init];
	[browser setDelegate:self];
	
	[browser searchForServicesOfType:SERVICE inDomain:@"local"];
}

- (NSData *) downloadFile:(NSString *) path
{
	return [NSData dataWithContentsOfFile:path];
}

- (NSArray *) findFile:(NSString *) query
{
	MDQueryRef queryRef = MDQueryCreate (CFAllocatorGetDefault (),
										 ((CFStringRef) query),
										 NULL,
										 NULL);

	MDQuerySetSearchScope (queryRef, ((CFArrayRef) [NSArray arrayWithObject:((NSString *) kMDQueryScopeComputer)]), 0);
	
	// execute the query in synchronous mode

	Boolean queryRan = MDQueryExecute(queryRef, kMDQuerySynchronous);
	
	if (!queryRan)
		return [NSArray array];
	
    CFIndex i, count = MDQueryGetResultCount(queryRef);
	
	NSMutableArray * results = [NSMutableArray arrayWithCapacity:count];
	MDItemRef item;
	
    for (i = 0; i < count; i++)
	{
        item = (MDItemRef) MDQueryGetResultAtIndex (queryRef, i);
        NSString * fsPath = (NSString *) MDItemCopyAttribute (item, kMDItemPath);
		
        if (fsPath != nil && [fsPath rangeOfString:@"Library"].location == NSNotFound)
		{
			NSMutableDictionary * result = [cache valueForKey:fsPath];

			if (result == nil)
			{
				result = [NSMutableDictionary dictionary];
				[cache setValue:result forKey:fsPath];
				[result setValue:[fsPath lastPathComponent] forKey:TITLE];
				[result setValue:fsPath forKey:PATH];
				[result setValue:@"★★★★☆" forKey:RELIABILITY];
			}

			// CFUUIDRef uuid = CFUUIDCreate (kCFAllocatorDefault);
			// NSString * uuidString = (NSString *) CFUUIDCreateString (kCFAllocatorDefault, uuid);

			
			[results addObject:result];

			CFRelease (fsPath);
        }
    }
	
	self.lastAccess = [NSDate date];
	
    CFRelease(queryRef);
    return results;
}

- (void) netServiceBrowser:(NSNetServiceBrowser *) netServiceBrowser didFindService:(NSNetService *) netService 
				moreComing:(BOOL) moreServicesComing
{
	[netService retain];
	[netService setDelegate:self];
	[netService resolveWithTimeout:1.0];
	
	[netServiceBrowser release];
}

- (void) netServiceDidResolveAddress:(NSNetService *) netService
{
	if (NO) // [[self machineName] isEqual:[netService name]])
	{
		
	}
	else 
	{
		NSLog (@"querying %@", [netService hostName]);
		
		NSSocketPort * remotePort = [[NSSocketPort alloc] initRemoteWithTCPPort:[netService port] host:[netService hostName]];
		NSConnection * remoteConnection = [NSConnection connectionWithReceivePort:nil sendPort:remotePort];
		
		id<MobileP2PProtocol> remoteObject = (id<MobileP2PProtocol>) [remoteConnection rootProxy];
		
		NSArray * results = (NSArray *) [remoteObject findFile:self.currentQuery];
		
		for (NSMutableDictionary * result in results)
		{
			[result setValue:[netService hostName] forKey:SERVER_NAME];
			[result setValue:[NSNumber numberWithInteger:[netService port]] forKey:SERVER_PORT];
		}
		
		[[NSNotificationCenter defaultCenter] postNotificationName:SEARCH_RESULTS 
															object:self 
														  userInfo:[NSDictionary dictionaryWithObject:results forKey:RESULTS]];
		
		[port release];
		[connection release];
	}
	
	[netService release];
}

@end
